#!/usr/bin/env node
var exec = require('child_process').exec;
//var readStandardFile=require('./readstandard')
// var static = require('./node-static');
// var file = new static.Server('./build');
var debug = require('debug')('express-example');
var models = require("./models");
var ss = require('socket.io-stream');
var path=require('path');
var fs=require('fs');
const { StringDecoder } = require('string_decoder');
const decoder = new StringDecoder('utf8');
console.log(path.resolve(__dirname));
//console.log(path)
var app_root=path.resolve(".");
//app_root=app_root.replace(/\\/g, "/");
//var  app_root=path.normalize(".")
//console.log(app_root)
function deleteFolder(path) {
    var files = [];
    if( fs.existsSync(path) ) {
        files = fs.readdirSync(path);
        files.forEach(function(file,index){
            var curPath = path + "/" + file;
            if(fs.statSync(curPath).isDirectory()) { // recurse
                deleteFolder(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
}
function path_isdir(p){
    var stat=fs.statSync(p);
    if(stat.isDirectory()){
      return true;
    }
    return false;
}
function toPath(p){
    var stat=fs.statSync(p);
    // console.log("=toPath===============")
    // console.log(app_root)
    // console.log(p);
    var lp=p.substring(app_root.length+1);
    lp="./"+lp;
    if(stat.isDirectory()){
      return {"path": lp,
            "name": path.basename(p),
            "time": stat.mtimeMs,
            "isdir": true,
            "size":Number.MAX_VALUE};
      }
    else{
      return {"path": lp,
            "name": path.basename(p),
            "time": stat.mtimeMs,
            "isdir": false,
            "size":stat.size};
      }
}
//console.log(toPath("run.bat"))
//console.log(toPath("static"))
function toLocalPath(path1){
    var fsPath = path.resolve(app_root, path1);
    fsPath=fsPath.replace(/\\/g, "/");
    console.log(fsPath);
    //if(os.path.commonprefix([app_root, fsPath]) != app_root){
    //    raise Exception("Unsafe path "+ fsPath+" is not a  sub-path  of root "+ app_root)
    //}
    return fsPath;
}
//toLocalPath("abc")
function toWebPath(path){
     return "/static/"+path;
}
function children(path1){
    console.info(path1);
    var p = toLocalPath(path1);
    if (fs.existsSync(p)){

    }
    else{
        p= toLocalPath(".");
    }
    var children = fs.readdirSync(p);
    var children_stats=children.map((one, idx) =>{
        var p1=p+"/"+one;
        return toPath(p1);
    });
    dic={"path": p,"children": children_stats};
    return dic;
}
//console.info(children("."))
function parent(path1){
  var isroot=false;
  let parent1= path.dirname(path1);
  if(path1==="."){
      isroot=true;
  }
  var dic=toPath(parent1);
  dic.isroot=isroot;
  return dic;
}
function remove(path1){
    var curPath = toLocalPath(path1);
    if(fs.statSync(curPath).isDirectory()) { // recurse
        deleteFolder(curPath);
    } else { // delete file
        fs.unlinkSync(curPath);
    }
    return {status:"success"};
}
function rename(path1,name){
  var p = toLocalPath(path1);
  var parent = path.dirname(p);
  var updated = path.join(parent, name);
  fs.renameSync(p, updated);
  return {status:"success"};
}
function content(path1){
  var p = toLocalPath(path1);
  var r=fs.readFileSync(p);
  return decoder.write(r);
}

function mkdir(path1,foldername){
  var p = toLocalPath(path1);
  fs.mkdirSync(path.join(p, foldername));
  return {status:"success"};
}
function DateStr(date) {
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var s_month=""+month;
    if (s_month.length<2) s_month="0"+s_month;
    var day = date.getDate();
    var s_day=""+day;
    if (s_day.length<2) s_day="0"+s_day;
    return year + "-" + s_month + "-" + s_day ;
}
const sequelize_serv=()=>{
  console.log("listen");
  var finalhandler = require('finalhandler')
  var http = require('http')
  var serveIndex = require('serve-index')
  var serveStatic = require('serve-static')

  // Serve directory indexes for public/ftp folder (with icons)
  var index = serveIndex('.', {'icons': true})

  // Serve up public/ftp folder files
  var serve = serveStatic('.')

  // Create server
  var server = http.createServer(function onRequest(req, res){
    var done = finalhandler(req, res)
    serve(req, res, function onNext(err) {
      if (err) return done(err)
      index(req, res, done)
    })
  })
  //socket.io
  const socket_serv=( socket )=>{
    console.log('connection');
    console.log('connection');
    socket.on('/fs/children', function( data, callback ) {       
      console.log("list");
      console.log(data);
      callback(children(data.path));
    });
    socket.on('parent', function( data, callback ) {       
      console.log("parent")
      console.log(data);
      callback(parent(data.path));
    });
    socket.on('mkdir', function( data, callback ) {       
      console.log("mkdir")
      console.log(data);
      callback(mkdir(data.path,data.name));
    });
    socket.on('rename', function( data, callback ) {       
      console.log("rename")
      console.log(data);
      callback(rename(data.path,data.name));
    });
    socket.on('remove', function( data, callback ) {       
      console.log("remove")
      console.log(data);
      callback(remove(data.path));
    });
    socket.on('content', function( data, callback ) {       
      console.log("content")
      console.log(data);
      callback(content(data.path));
    });  
    socket.on('savefile', function( data, callback ) {       
      console.log("savefile")
      console.log(data);
      var p = toLocalPath(data.path);
      var stream=fs.createWriteStream(p)
      stream.write(data.content,"utf-8");
      stream.end();
      callback({success:true});
    });  
    ss(socket).on('upload', function(stream, data,callback) {
      var p = toLocalPath(data.path);
      var filename=path.join(p,data.name);
      stream.pipe(fs.createWriteStream(filename));
      // var buffers = [];
      // stream.on('data', function(data) { buffers.push(data); });
      stream.on('end', function() {
           callback({success:true});
      });
    });    
    ss(socket).on('file', function(stream, data,callback) {
      var buffers = [];
      stream.on('data', function(data) { buffers.push(data); });
      stream.on('end', function() {
          var buffer = Buffer.concat(buffers);
          readStandardFile(buffer,data.name,callback)
      });
    });    
    socket.on('/folder', function( data, callback ) {
              models.emit("/get/folder",data,callback)
    });    
    socket.on('/post/standard', function( data, callback ) {
              models.emit("/post/standard",data,callback)
    }); 
    socket.on('/get/month12', async function( data, callback ) {
              models.emit("/get/month12",data,callback)
    });
    socket.on('/get/year12', async function( data, callback ) {
              models.emit("/get/year12",data,callback)
    });
    socket.on('/parts/showcontact', async function( data, callback ) {  
              models.emit("/parts/showcontact",data,callback)
    }); //delete
    socket.on('/delete/Contact', async function( data, callback ) { 
      models.emit("/delete/Contact",data,callback)
    }); //delete
    socket.on('/post/Contact', async function( data, callback ) {   
              models.emit("/post/Contact",data,callback)
    });
    socket.on('/put/Contact', async function( data, callback ) {      
              models.emit("/put/Contact",data,callback)
    });
    socket.on('/get/Contact', async function( data, callback ) {        
              models.emit('/get/Contact', data, callback) 
    });
    socket.on('/delete/UsePack', async function( data, callback ) { 
              models.emit('/delete/UsePack', data, callback) 
    }); //delete
    socket.on('/post/UsePack', async function( data, callback ) {       
              models.emit('/post/UsePack', data, callback) 
    });
    socket.on('/put/UsePack', async function( data, callback ) {        
              models.emit('/put/UsePack', data, callback) 
    });
    socket.on('/post/UsePackEx', async function( data, callback ) {       
              models.emit('/post/UsePackEx', data, callback) 
          });
    socket.on('/post/PackItemEx', async function( data, callback ) {        
      models.emit('/post/PackItemEx', data, callback) 
     });
    socket.on('/get/UsePack', async function( data, callback ) {        
              models.emit('/get/UsePack', data, callback) 
    });
    socket.on('/delete/PackItem', async function( data, callback ) {        
              models.emit('/delete/PackItem', data, callback) 
    }); //delete
    socket.on('/post/PackItem', async function( data, callback ) {        
              models.emit('/post/PackItem', data, callback) 
    });
    socket.on('/put/PackItem', async function( data, callback ) {       
              models.emit('/put/PackItemEx', data, callback) 
    }); //update
    socket.on('/get/PackItem', async function( data, callback ) { 
              models.emit('/get/PackItem', data, callback) 
    });
    socket.on('/post/Pack', async function( data, callback ) {        
              models.emit('/post/Pack', data, callback) 
    });
    //route.get('/rest/Pack', async function(ctx,next) {
    socket.on('/get/Pack', async function( data, callback ) {       
              models.emit('/get/Pack', data, callback) 
    });
    //Item
    //route.post('/rest/Item', async function(ctx,next) {
    socket.on('/post/Item', async function( data, callback ) {        
              models.emit('/post/Item', data, callback) 
    });
    socket.on('/put/Item', async function( data, callback ) {        
              models.emit('/put/Item', data, callback) 
    });
    socket.on('/get/Item', async function( data, callback ) {       
              models.emit('/get/Item', data, callback) 
          });
    socket.on('/get/sql', async function( data, callback ) {       
                  models.emit('/sql', data, callback) 
    });
    socket.on('/multi', async function( data, callback ) {       
                  models.emit('/multi', data, callback) 
    });
    socket.on('/users', async function( data, callback ) {       
                  models.emit('/users', data, callback) 
    });
    var userNames = (function () {
      var names = {};

      var claim = function (name) {
        if (!name || names[name]) {
          return false;
        } else {
          names[name] = true;
          return true;
        }
      };

      // find the lowest unused "guest" name and claim it
      var getGuestName = function () {
        var name,
          nextUserId = 1;

        do {
          name = 'Guest ' + nextUserId;
          nextUserId += 1;
        } while (!claim(name));

        return name;
      };

      // serialize claimed names as an array
      var get = function () {
        var res = [];
        for (user in names) {
          res.push(user);
        }

        return res;
      };

      var free = function (name) {
        if (names[name]) {
          delete names[name];
        }
      };

      return {
        claim: claim,
        free: free,
        get: get,
        getGuestName: getGuestName
      };
    }());

    var name = userNames.getGuestName();

    // send the new user their name and a list of users
    socket.emit('init', {
      name: name,
      users: userNames.get()
    });

    // notify other clients that a new user has joined
    socket.broadcast.emit('user:join', {
      name: name
    });

    // broadcast a user's message to other users
    socket.on('send:message', function (data) {
      socket.broadcast.emit('send:message', {
        user: name,
        text: data.text
      });
    });

    // validate a user's name change, and broadcast it on success
    socket.on('change:name', function (data, fn) {
      if (userNames.claim(data.name)) {
        var oldName = name;
        userNames.free(oldName);

        name = data.name;
        
        socket.broadcast.emit('change:name', {
          oldName: oldName,
          newName: name
        });

        fn(true);
      } else {
        fn(false);
      }
    });

    // clean up when a user leaves, and broadcast it to other users
    socket.on('disconnect', function () {
      socket.broadcast.emit('user:left', {
        name: name
      });
      userNames.free(name);
    });
  }
  // Listen
  server.listen(8000)
  console.log('node-static & socket.io server listening on port 8000');
  const io = require('socket.io')(server);
  io.sockets.on('connection', socket_serv);
}
models.sequelize.sync().then(sequelize_serv);

